//
//  DGGlobalTimerObserverManager.m
//  DGGlobalTimer
//
//  Created by Jinxiao on 7/25/14.
//  Copyright (c) 2014 debugeek. All rights reserved.
//

#import "DGGlobalTimerObserverManager.h"
#import "DGGlobalTimerObserver.h"
#import "DGGlobalTimerTask.h"
#import "DGGlobalTimerTaskManager.h"

@interface DGGlobalTimerObserverManager ()
@property (readwrite, nonatomic, retain) NSMutableDictionary *groups;
@end

@implementation DGGlobalTimerObserverManager

+ (instancetype)sharedInstance
{
    static id instance;
    static dispatch_once_t once;
    dispatch_once(&once, ^{
        instance = self.new;
    });
    return instance;
}

- (instancetype)init
{
    self = [super init];
    if(self)
    {
        _groups = [[NSMutableDictionary alloc] init];
    }
    return self;
}

- (DGGlobalTimerObserver *)observerForIdentifier:(NSString *)identifier
{
    __block DGGlobalTimerObserver *observer = nil;
    [_groups enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
        [((NSArray *)obj) enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            if([((DGGlobalTimerObserver *)obj).identifier isEqualToString:identifier])
            {
                observer = obj;
                *stop = YES;
            }
        }];
        *stop = observer != nil;
    }];
    return observer;
}

- (BOOL)addGlobalTimerObserver:(DGGlobalTimerObserver *)observer
{
    if(!observer)
    {
        return NO;
    }
    
    NSMutableArray *observers = [_groups objectForKey:observer.key];
    if(!observers)
    {
        observers = [[NSMutableArray alloc] init];
        [_groups setObject:observers forKey:observer.key];
    }
    
    __block BOOL exist = NO;
    [observers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if([((DGGlobalTimerObserver *)obj).identifier isEqualToString:observer.identifier])
        {
            exist = YES;
            *stop = YES;
        }
    }];
    
    if(!exist)
    {
        [observers addObject:observer];
        
        DGGlobalTimerTask *task = [[DGGlobalTimerTaskManager sharedInstance] timerTaskForKey:observer.key];
        if(task)
        {
            NSTimeInterval elapsed = [[NSDate date] timeIntervalSince1970] - task.fired;
            NSTimeInterval remains = task.duration - elapsed;
            
            if(remains <= 0 && observer.completedBlock)
            {
                observer.completedBlock();
            }
            else if(observer.initializedBlock)
            {
                observer.initializedBlock(remains);
            }
        }
        else if(observer.preparedBlock)
        {
            observer.preparedBlock();
        }
    }
    
    return !exist;
}

- (BOOL)removeGlobalTimerObserver:(DGGlobalTimerObserver *)observer
{
    if(!observer)
    {
        return NO;
    }
    
    NSMutableArray *observers = [_groups objectForKey:observer.key];
    if(observers)
    {
        NSMutableArray *matches = [NSMutableArray array];
        [observers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            if([((DGGlobalTimerObserver *)obj).identifier isEqualToString:observer.identifier])
            {
                [matches addObject:obj];
            }
        }];
        [observers removeObjectsInArray:matches];
    }
    
    return YES;
}

- (void)dispatchPreparedActionForKey:(NSString *)key
{
    NSMutableArray *observers = [_groups objectForKey:key];
    [observers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if(((DGGlobalTimerObserver *)obj).preparedBlock)
        {
            ((DGGlobalTimerObserver *)obj).preparedBlock();
        }
    }];
}

- (void)dispatchInitializedActionForKey:(NSString *)key remains:(NSTimeInterval)remains
{
    NSMutableArray *observers = [_groups objectForKey:key];
    [observers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if(((DGGlobalTimerObserver *)obj).initializedBlock)
        {
            ((DGGlobalTimerObserver *)obj).initializedBlock(remains);
        }
    }];
}

- (void)dispatchTriggeredActionForKey:(NSString *)key remains:(NSTimeInterval)remains
{
    NSMutableArray *observers = [_groups objectForKey:key];
    [observers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if(((DGGlobalTimerObserver *)obj).triggeredBlock)
        {
            ((DGGlobalTimerObserver *)obj).triggeredBlock(remains);
        }
    }];
}

- (void)dispatchCompletedActionForKey:(NSString *)key
{
    if (!key) {
        return;
    }
    
    NSMutableArray *observers = [_groups objectForKey:key];
    [observers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if(((DGGlobalTimerObserver *)obj).completedBlock)
        {
            ((DGGlobalTimerObserver *)obj).completedBlock();
        }
    }];
}

@end
